//      Copyright (c) Microsoft Corporation. All rights reserved.
#pragma once
#include <windows.h>
#include <stddef.h>
#include <wsdapi.h>
#include <string>
#include <functiondiscovery.h>
#include <functiondiscoverykeys.h>
#include "SideShowServiceType.h"
#include "SideShowServiceTypeProxy.h"

class CDPWSSideShow;
class CSideShowButtonEventSink;

HRESULT GetFunctionInstancePNPXID(IFunctionInstance* pFunInst, wstring& deviceID);

class CDeviceProxyProvider
{
public:
    CDeviceProxyProvider();
    ~CDeviceProxyProvider();
    HRESULT Initialize(const wstring& clientID, CSideShowButtonEventSink *pEventSink);
    HRESULT UpdateProxy(const wstring& deviceID);
    void GetProxy(CComPtr<ISideShowServiceTypeProxy>& pProxy);
private:
    void SetProxy(const CComPtr<ISideShowServiceTypeProxy>& pProxy);
    void SendRenderAgain();
    HRESULT CreateProxy(const wstring& deviceID, CComPtr<ISideShowServiceTypeProxy>& pProxy);
    HRESULT SubscribeToEvents(ISideShowServiceTypeProxy* pProxy);
    HRESULT UnsubscribeToEvents(ISideShowServiceTypeProxy* pProxy);

    CComPtr<ISideShowServiceTypeProxy> m_pDeviceProxy;
    CComPtr<ISideShowServiceTypeEventNotify> m_pDPWSEventSink;
    CSideShowButtonEventSink* m_pEventSink;
    CRITICAL_SECTION m_CriticalSection;
};

class CDeviceDiscovery;

class CFunctionDiscoveryListener :
    public IFunctionDiscoveryNotification
{
public:
    CFunctionDiscoveryListener(const wstring& deviceID, CDeviceProxyProvider* pDeviceProxyProvider);
private:    
    ~CFunctionDiscoveryListener();

    // IUnknown implementations 
public:
    HRESULT ( STDMETHODCALLTYPE QueryInterface )( 
        /* [in] */ __RPC__in REFIID riid,
        /* [iid_is][out] */ 
        __RPC__deref_out  void **ppvObject);

    ULONG ( STDMETHODCALLTYPE AddRef )( );

    ULONG ( STDMETHODCALLTYPE Release )( );

    // IFunctionDiscoveryNotification implementations
public:


    HRESULT ( STDMETHODCALLTYPE OnUpdate )( 
        /* [in] */ QueryUpdateAction enumQueryUpdateAction,
        /* [in] */ FDQUERYCONTEXT fdqcQueryContext,
        /* [in] */ __RPC__in_opt IFunctionInstance *pIFunctionInstance);

    HRESULT ( STDMETHODCALLTYPE OnError )( 
        /* [in] */ HRESULT hr,
        /* [in] */ FDQUERYCONTEXT fdqcQueryContext,
        /* [string][in] */ __RPC__in const WCHAR *pszProvider);

    HRESULT ( STDMETHODCALLTYPE OnEvent )( 
        /* [in] */ DWORD dwEventID,
        /* [in] */ FDQUERYCONTEXT fdqcQueryContext,
        /* [string][in] */ __RPC__in const WCHAR *pszProvider);

private:
    LONG m_cRef;
    CDeviceProxyProvider *m_pDeviceProxyProvider;
    wstring m_deviceID;
};

class CDeviceDiscovery
{
public: 
    CDeviceDiscovery();
    HRESULT Initialize(const wstring& instance, CDeviceProxyProvider* pDeviceProxyProvider);
private:
    HRESULT GetDevicePNPXID(const wstring& instance, wstring& deviceID);
    HRESULT StartListener(CFunctionDiscoveryListener* listener);

    CComPtr<IFunctionDiscovery> m_pFunctionDiscovery;
    CComPtr<IFunctionInstanceCollectionQuery> m_pFunInstsQuery;
};

